home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 25
/
Mac Magazin and MacEasy Magazine CD - Issue 25.iso
/
Grafik & Text
/
BibTeX
/
Source code
/
bibutils.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-03
|
40KB
|
821 lines
//###################################################################
//
// FILE: "bibutils.cc"
// created: 31/1/96 {12:23:51 am}
// last update: 3/6/96 {9:55:57 pm}
// Author: Vince Darley
// E-mail: <mailto:vince@das.harvard.edu>
// mail: Division of Applied Sciences, Harvard University
// Oxford Street, Cambridge MA 02138, USA
// <http://www.das.harvard.edu/users/students/Vincent_Darley/>
//
// See header file for further information
//###################################################################
// Based on code from Rick Zaccone. This file is kind of an interface between the
// powerplant application and the BibTeX source code.
// There's old stuff hanging about which needs to be cleared out!
#include "bibutils.h"
#include "BibTeX.h"
#include "bibext.h"
#include "file-io.h"
#include "CBibTeXApp.h"
#include <LGrowZone.h>
int debug = FALSE;
int verbose = TRUE;
int BibTeX_dot = TRUE; /* flag which shows dot in ilg being active */
const char *aux_fn;
const char *dbg_fn;
FileDesc gAuxDesc;
FileDesc gDbgDesc;
// Local variables:
static char base[FILENAME_MAX];
long totmem = 0L; /* for debugging memory usage */
// Local functions:
static void Bibtex(void);
static void chknew(size_t size);
static void check_aux(char *fn);
static void FreeMemory(void);
static void InitializeBibtex(void);
#ifdef MAX
#undef MAX
#endif
#define MAX(a,b) ( ((a) > (b)) ? (a) : (b) )
/**************************************************************************
* *
* Function: InvokeBibtex *
* Purpose: This function merely invokes the main Bibtex function. *
* Inputs: None. *
* Outputs: None. *
* Exceptions: Catches any exceptions thrown inside of Bibtex. *
* Side Effects: None. *
* Design: This function is just a wrapper for Bibtex. It allows *
* me to catch any exceptions thrown while Bibtex does its *
* processing. *
* Errors: None. *
* History: *
* 1.0 29-Jul-95 RJZ. Initial version. *
* *
**************************************************************************/
void InvokeBibtex(void) {
// Any call to FATAL or FatalOSErr is
// caught by this exception handler.
try {
Bibtex();
}
catch (...) {
CloseAllFiles();
}
}
/**********************************************************************
* *
* Function: OneTimeInitialization *
* Purpose: Performs any initialization of Bibtex that needs to *
* happen just once at program start-up. *
* Inputs: None. *
* Outputs: Returns an error code if there was a problem with *
* initialization. *
* Exceptions: None. *
* Side Effects: None. *
* Errors: None. *
* History: *
* 1.0 29-Jul-95 RJZ. Initial version. *
* *
**********************************************************************/
OSErr OneTimeInitialization(void) {
OSErr err = noErr;
return err;
}
/************************************************************************
* *
* Function: InitializeBibtex *
* Purpose: This function performs initialization that must be done *
* every time we process a new aux file. It also invokes *
* initializers for all other Bibtex modules. *
* Inputs: None. *
* Outputs: None. *
* Exceptions: None. *
* Side Effects: Initializes plenty of global varialbes. *
* Design: Each module has its own initializer so that I don't have *
* to increase the scope of the global variables defined *
* within that module. *
* Errors: None. *
* History: *
* 1.0 29-Jul-95 RJZ. Initial version. *
* *
************************************************************************/
static void InitializeBibtex(void) {
// Initialize the file reference
// numbers to zero indicating that none
// of these files are open.
gAuxDesc.refNum = 0;
gDbgDesc.refNum = 0;
totmem = 0L;
}
/***********************************************************************
* *
* Function: Bibtex *
* Purpose: This is pretty much the entire Bibtex program. *
* Inputs: None. *
* Outputs: None. *
* Exceptions: Throws an exception if there is an OS error while *
* initializing. *
* Side Effects: Lots of them. They are all warts from the original *
* program. *
* Design: Original design by Pehong Chen. See copyright notice. *
* Errors: Prints error messages in the log window as they occur. *
* History: *
* 1.0 13-Jul-95 RJZ. Initial version. *
* *
***********************************************************************/
static void Bibtex(void) {
InitializeBibtex();
// The program name won\'t be coming
// from the command line, so set it
// here.
OSErr err;
extern FInfo AuxFileInfo; // Finder info for aux file
// Determine creator of aux file
err = ::FSpGetFInfo(&gAuxDesc.spec, &AuxFileInfo);
if (err != noErr)
FatalOSErr("Error getting Finder information for aux file: %s", err);
vince_main();
//FPrintFStdErr("Transcript written in %s.\r", blg_fn);
chkfree(); /* free dynamic chunk space */
CloseAllFiles();
}
/*--------------------------------------------------------------------*/
/***********************************************************************
malloc() implementations themselves usually allocate large chunks of
memory of fixed size in which they suballocate requests with
additional overhead of pointers, lengths, and alignment requirements.
Experiments with the program in tstmall.c indicate a typical policy of
aligning the request to a double-word boundary, then adding space for
two extra words. Thus, allocation of a single byte uses up 24 bytes!
When a large chunk is used up, another large chunk is allocated with
an additional overhead of two more words. Thus, we should allocate
our own chunks in sizes of malloc() large chunk sizes, less the
two-word/chunk malloc() overhead, and less our chunk pointer size. On
some systems, optimal choice of CHUNKSIZE is critical if space is not
to be seriously wasted; a value of 2048 is best for DECstation ULTRIX
4.3.
***********************************************************************/
#ifndef CHUNKSIZE /* can specify at compile time */
#define CHUNKSIZE 2048 /* suitable for most systems */
#if defined(__alpha) && defined(__unix__)
#undef CHUNKSIZE
#define CHUNKSIZE 2040 /* for DEC Alpha OSF/1 2.x */
#endif
#if defined(__host_mips) && defined(_SYSTYPE_SYSV) && !defined(__sgi)
#undef CHUNKSIZE
#define CHUNKSIZE 16892 /* weird size for MIPS RC6280 EP/IX 2.1.1 */
#endif
#endif /* CHUNKSIZE */
#ifndef MAXCHUNK
#define MAXCHUNK (CHUNKSIZE - 2*sizeof(void*) - 2*sizeof(void*))
#endif
typedef struct KCHUNK {
struct KCHUNK **prev; /* handle to previous chunk */
char *end; /* address of byte following end of storage[] */
char storage[1]; /* space for this chunk */
} CHUNK, *CHUNK_PTR, **ChunkHandle;
static ChunkHandle chkhead = (ChunkHandle) NULL; // Handle to chain of chunks
static char *chknext = (char*)NULL; /* next available in current chunk */
static long chktotal = 0L; /* total bytes allocated */
typedef struct chk_remember {
struct chk_remember *next;
char* offset;
ChunkHandle handle;
} chk_remember;
static chk_remember* chk_store_head = NULL;
static chk_remember* chk_store = NULL;
void unlockhandles(void) {
ChunkHandle ch;
for (ch = chkhead ;ch; ) {
HUnlock((Handle) ch);
ch = (**ch).prev;
}
}
void lockhandles(void) {
ChunkHandle ch;
for (ch = chkhead ;ch; ) {
HLockHi((Handle) ch);
ch = (**ch).prev;
}
}
extern CBibtexApp* theAppPointer;
void cede_time(void){
unlockhandles();
theAppPointer->ProcessNextEvent();
lockhandles();
}
/*********************************************************************
* *
* Function: FreeMemory *
* Purpose: Frees the memory chunks that we have allocated. *
* Inputs: None. *
* Outputs: None. *
* Exceptions: None. *
* Side Effects: Frees memory and changes the value of some global *
* variables. *
* Errors: None. *
* History: *
* 1.1 16-Mar96 RJZ. Initial version. *
* *
*********************************************************************/
static void FreeMemory(void) {
ChunkHandle oldChunkHead;
while (chkhead != (ChunkHandle) NULL) {
oldChunkHead = chkhead;
chkhead = (**chkhead).prev;
DisposeHandle((Handle) oldChunkHead);
}
chktotal = 0L;
chkhead = (ChunkHandle) NULL;
chknext = (char *) NULL;
chk_remember* next_chk_store;
for(chk_store = chk_store_head; chk_store; ){
next_chk_store = chk_store->next;
delete chk_store;
chk_store = next_chk_store;
}
}
/**************************************************************************
* *
* Function: chkalloc *
* Purpose: Allocates a chunk of memory. *
* Inputs: size is the number of bytes to allocate. alignment_size *
* specifies how the chunk should be aligned in memory. 1 = *
* byte, 2 = short, 4 = long. *
* Outputs: Returns a pointer to the memory allocated. *
* Exceptions: None. *
* Side Effects: Allocates memory. *
* Design: First try to allocate the memory in the application heap. *
* If that fails, allocate the memory in the system heap. *
* Note that after allocating this handle based memory, it *
* must remain locked until it is freed. *
* Errors: None. *
* History: *
* 1.0 20-Jul-95 RJZ. Changed this function so that the chunks *
* are handle based rather than pointed based. *
* *
**************************************************************************/
void *chkalloc(size_t size, size_t alignment_size) {
char *p;
// If the head of the chunk list is
// NULL, then this is the first call.
if (chkhead == (ChunkHandle) NULL){
chknew(size);
// store the first one so we can zip through the
// list later front to back to find out pointers
// again
chk_store_head = new chk_remember;
chk_store = 0;
}
if (alignment_size < 1)
alignment_size = 1;
chknext = (char*)((long)(chknext + alignment_size - 1) &
~(alignment_size - 1));
if ((chknext + size) > (**chkhead).end)
chknew(size);
p = chknext;
chknext += size;
if(chk_store != 0) {
chk_store->next = new chk_remember;
chk_store = chk_store->next;
} else {
chk_store = chk_store_head;
}
// remember what we did
chk_store->handle = chkhead;
chk_store->offset = (char*) (p - ((**chkhead).storage));
chk_store->next = 0;
return ((void*)p);
}
void *ptohrealloc(short reset) {
static chk_remember* chk_iterator;
if(reset == 1){
chk_iterator = chk_store_head;
return 0;
}
char* p;
p = (char*) ( (long)((**(chk_iterator->handle)).storage)
+ (long)(chk_iterator->offset));
chk_iterator = chk_iterator->next;
return p;
}
/************************************************************************
* *
* Function: chkfree *
* Purpose: Frees all the dynamically allocated chunks of memory. *
* Inputs: None. *
* Outputs: None. *
* Exceptions: None. *
* Side Effects: Frees memory. Writes the total number of bytes *
* allocated to the message window and the log file. *
* Design: The chunks of memory form a linked list. Start at the *
* head of the list and free each chunk. *
* Errors: None. *
* History: *
* 1.0 20-Jul-95 RJZ. Changed this function so that it knows *
* that the chunks are handle based. *
* 1.1 16-Mar-96 RJZ. The freeing of the memory is in a *
* separate function now. *
* *
************************************************************************/
void chkfree(VOID_ARG) {
MESSAGE("Dynamic memory allocated: %ld bytes.\r", chktotal);
FPrintFStdErr("\rBibTeX run complete.\r");
FreeMemory();
}
/**************************************************************************
* *
* Function: chknew *
* Purpose: Allocates a new chunk of memory. *
* Inputs: size is the size of the memory to be allocated. *
* Outputs: None. *
* Exceptions: Throws an exception if unable to allocate the memory. *
* Side Effects: Dynamically allocates memory. *
* Design: First try to allocate a block of memory in the application *
* heap. If that fails, try using temporary memory. This is *
* the only place that Bibtex allocates memory. *
* Errors: Writes an error message if both allocations fail. *
* History: *
* 1.0 20-Jul-95 RJZ. Changed so that the blocks are handle *
* based. This allows Bibtex to use temporary *
* memory if the application memory is exhausted. *
* 1.1 16-Mar-96 RJZ. If memory allocation fails, free memory *
* before printing an error message. This helps *
* to insure that the message will appear! Also, *
* allocate temp memory first. When that's *
* finished, begin allocating from the *
* application heap. Only use the application *
* heap if the memory reserve is still available. *
* *
**************************************************************************/
static void chknew(size_t size) {
size_t chunk_size;
OSErr err;
ChunkHandle new_chkhead;
chunk_size = MAX(size,MAXCHUNK) + sizeof(ChunkHandle) + sizeof(char*);
new_chkhead = (ChunkHandle) TempNewHandle(chunk_size, &err);
if (new_chkhead == NULL) {
LGrowZone *growZone = LGrowZone::GetGrowZone();
if (!growZone->MemoryIsLow())
new_chkhead = (ChunkHandle) NewHandle(chunk_size);
}
// When memory is exhausted, tell the
// user how far we got before quitting.
if (new_chkhead == (ChunkHandle) NULL) {
FreeMemory();
err = MemError();
MESSAGE("Current input file = %s\r", aux_fn);
//MESSAGE("Current line number = %ld\r", (long)BibTeX_lc);
//MESSAGE("Current entry total = %ld\r", (long)BibTeX_tt);
FATAL("Not enough core...abort.\r%s", "");
}
HLockHi((Handle) new_chkhead);
// track total bytes allocated
chktotal += chunk_size;
// for debugging only
(void) memset(*new_chkhead,-1,chunk_size);
// attach to head of chunk chain
(**new_chkhead).prev = chkhead;
chkhead = new_chkhead;
(**chkhead).end = (char *) *chkhead + (int)chunk_size;
// chknext points to the next available
// byte in the storage area. For a new
// chunk, this is just the first byte.
chknext = (**chkhead).storage;
}
/**************************************************************************
* *
* Function: FormatOSErr *
* Purpose: Formats a Macintosh OS error into a C string. *
* Inputs: error is a non-zero OS error returned by an OS call. *
* buffer points to a buffer where the text equivalent of the *
* error code should be stored. *
* Outputs: buffer gets filled with the text equivalent of the error *
* code. *
* Exceptions: None. *
* Side Effects: None. *
* Design: This function knows the meaning of the most common error *
* messages. If it encounters one it doesn't know, it *
* converts the number to a string and uses that. *
* Errors: None. *
* History: *
* 1.0 10-Jul-95 RJZ. Original version. *
* *
**************************************************************************/
void FormatOSErr(OSErr error, char *buffer) {
char *errorString = NULL;
switch (error) {
case dirFulErr: // -33
errorString = "File directory full";
break;
case dskFulErr: // -34
errorString = "Disk is full";
break;
case nsvErr: // -35
errorString = "No such volume";
break;
case ioErr: // -36
errorString = "I/O error";
break;
case bdNamErr: // -37
errorString = "Bad filename";
break;
case fnOpnErr: // -38
errorString = "File not open";
break;
case eofErr: // -39
errorString = "End of file";
break;
case tmfoErr: // -42
errorString = "Too many files open";
break;
case fnfErr: // -43
errorString = "File not found";
break;
case wPrErr: // -44
errorString = "Hardware volume lock";
break;
case fLckdErr: // -45
errorString = "File is locked";
break;
case vLckdErr: // -46
errorString = "Software volume lock";
break;
case fBsyErr: // -47
errorString = "File is busy";
break;
case dupFNErr: // -48
errorString = "Duplicate filename and version";
break;
case opWrErr: // -49
errorString = "File already open for writing";
break;
case paramErr: // -50
errorString = "No default volume";
break;
case rfNumErr: // -51
errorString = "Bad reference number";
break;
case permErr: // -54
errorString = "Attempt to open locked file for writing";
break;
case nsDrvErr: // -56
errorString = "No such drive";
break;
case wrPermErr: // -61
errorString = "Write permission error";
break;
case dirNFErr: // -120
errorString = "Directory not found or incomplete pathname";
break;
case afpAccessDenied: // -5000
errorString = "User does not have the correct access";
break;
case afpObjectTypeErr: // -5025
errorString = "Directory not found or incomplete pathname";
break;
default:
NumToString(error, (StringPtr) buffer);
(void) P2CStr((StringPtr) buffer);
break;
}
if (errorString != NULL)
strcpy(buffer, errorString);
}
/**************************************************************************
* *
* Function: FatalOSErr *
* Purpose: Formats and prints a fatal error that occurs as the result *
* of an OS call. *
* Inputs: mess points to the first argument of a call to fprintf. *
* error is the OS error that occurred. In the overloaded *
* versions, the additional inputs are inputs to fprintf. *
* Outputs: None. *
* Exceptions: Throws an exception. Note that "throw" needs an argument *
* unless it is used within a catch handler. Use a dummy *
* NULL argument here. *
* Side Effects: Prints an error message. *
* Errors: Prints an error message. *
* History: *
* 1.0 10-Jul-95 RJZ. Initial version. *
* *
**************************************************************************/
void CloseAllFilesAfterError(void);
void FatalOSErr(const char *mess, OSErr error) {
char buffer[kBufferSize];
Str255 message;
FormatOSErr(error, buffer);
message[0] = sprintf((char *) message + 1, mess, buffer);
CBibtexApp::PostErrorAlert(message);
CloseAllFilesAfterError();
throw NULL;
}
void FatalOSErr(const char *mess, const char *mess1, OSErr error) {
char buffer[kBufferSize];
Str255 message;
FormatOSErr(error, buffer);
message[0] = sprintf((char *) message + 1, mess, mess1, buffer);
CBibtexApp::PostErrorAlert(message);
CloseAllFilesAfterError();
throw NULL;
}
/**************************************************************************
* *
* Function: ReportOSErr *
* Purpose: Formats and displays an error message. This is just like *
* FatalOSErr except that it is not fatal. *
* Inputs: mess is a pointer to a message string. error is an OSErr. *
* This function converts OSErr to a string and then inserts *
* it into mess where the %s appears. *
* Outputs: None. *
* Exceptions: None. *
* Side Effects: Displays an alert. *
* Errors: None. *
* History: *
* 1.0 29-Jul-95 RJZ. Initial version. *
* *
**************************************************************************/
void ReportOSErr(const char *mess, OSErr error) {
char buffer[kBufferSize];
Str255 message;
FormatOSErr(error, buffer);
message[0] = sprintf((char *) message + 1, mess, buffer);
CBibtexApp::PostErrorAlert(message);
}
/************************************************************************
* *
* Function: CloseAllFiles *
* Purpose: Closes all files that Bibtex may be using. CloseFile *
* checks to see if the file is actually open before trying *
* to close it, so there's no harm in calling it for every *
* file that Bibtex might be using. *
* Inputs: None. *
* Outputs: None. *
* Exceptions: None. *
* Side Effects: May close files. *
* Errors: None. *
* History: *
* 1.0 29-Jul-95 RJZ. Initial version. *
* *
************************************************************************/
void CloseAllFiles(void) {
CloseOutputFile(&gDbgDesc);
CloseAllFilesAfterError();
}
/**************************************************************************
* *
* Function: SetBibtexOptions *
* Purpose: Sets Bibtex options to the values indicated by its *
* parameters. *
* Inputs: germanOrdering is the same as the original -g option, *
* compressBlanks is the -c option, letterOrdering is the -l *
* option, and debugOn is the -d option. initPage is the -p *
* option. If evenOdd is -1, then pageNo contains a starting *
* page number. If evenOdd is 0, then the user has selected *
* the "any" option. If evenOdd is 1, the user has selected *
* the "odd" option. If evenOdd is 2, the user has selected *
* the "even" option. *
* Outputs: None. *
* Exceptions: None. *
* Side Effects: All option variables are global. This function sets *
* them. *
* Design: Since pageNo is a Pascal string, it may contain as many as *
* 255 characters. If this string is longer than *
* NUMBER_MAX-1, quietly truncate it. If the user tried to *
* enter a starting page number but didn't actually type a *
* number, use zero instead. *
* Errors: None. *
* History: *
* 1.0 29-Jul-95 RJZ. Initial version. *
* *
**************************************************************************/
void SetBibtexOptions(Boolean debugOn)
{
debug = debugOn;
}
/************************************************************************
* *
* Function: GetBibtexOptions *
* Purpose: Gets the current settings of Bibtex options. The *
* application calls this function so it can initialize the *
* values of the options before displaying the options *
* dialog. *
* Inputs: None. *
* Outputs: They are the same as the input parameters for *
* SetBibtexOptions. *
* Exceptions: None. *
* Side Effects: None. *
* Errors: None. *
* History: *
* 1.0 29-Jul-95 RJZ. Initial version. *
* *
************************************************************************/
void GetBibtexOptions(Boolean& debugOn)
{
debugOn = debug == TRUE;
}
/**************************************************************************
* *
* Function: GetWindowTitle *
* Purpose: Determines the title of the log window. *
* Inputs: None. *
* Outputs: outName is the title that the log window will have. *
* Exceptions: None. *
* Side Effects: None. *
* Design: Note that this function relies on base having an *
* appropriate value. This means that there should have been *
* a call to IntroduceIdxFile. *
* Errors: None. *
* History: *
* 1.0 29-Jul-95 RJZ. Initial version. *
* *
**************************************************************************/
void GetWindowTitle(StringPtr outName) {
outName[0] = sprintf((char *) outName + 1, "Log for \"%s\"", base);
}
/**************************************************************************
* *
* Function: check_aux *
* Purpose: Extracts the base name of the idx file (everything to the *
* left of ".idx") and tries to open the file if open_fn is *
* true. Also determines the size of the idx file. Be sure *
* to call this function immediately after getting the name *
* of the idx file. *
* Inputs: fn is a pointer the idx file name. open_fn is true if we *
* should try to open the file, false otherwise. *
* Outputs: None. *
* Exceptions: If this function is unable to open the file or unable to *
* determine the size of the file, it throws an exception. *
* Side Effects: Sets the value of "base" which is the base name of the *
* idx file. Also sets the value of gIdxFileSize to the *
* number of bytes in the idx file. *
* Design: In its original form, this function expected fn to be a *
* path to the idx file. The Macintosh file system does not *
* normally use a path to specify a file. Instead it uses an *
* File System Specification (FSSpec) record. This function *
* expects that the FSSpec record for the idx file (gIdxSpec) *
* has been filled in prior to entry. fn points to just the *
* file name and it is no longer a path to the file. *
* *
* Note that some of the error conditions that this function *
* checks will no longer occur. For example, the file name *
* will never be too long (since the user selected the file *
* via a StandardGetFile dialog). Also, if the function that *
* opens the file fails, it will throw an exception. We will *
* never see a return code of 0 from OPEN_IN. *
* Errors: Reports an error if unable to determine the size of the *
* file. *
* History: *
* 1.0 10-Jul-95 RJZ. Replaced most Unix I/O calls with their *
* Macintosh equivalents. The ones that remain *
* will never get called. This function now *
* determines the size of the idx file. This is *
* so Bibtex can buffer the input from this *
* file. *
* *
**************************************************************************/
static void check_aux(char *fn) {
char *ptr = fn;
char *ext;
int with_ext = FALSE;
int i = 0;
ext = strrchr(fn, EXT_DELIM);
if ((ext != NULL) && (ext != fn) && (*(ext + 1) != DIR_DELIM)) {
with_ext = TRUE;
while ((ptr != ext) && (i < sizeof(base)))
base[i++] = *ptr++;
} else
while ((*ptr != NUL) && (i < sizeof(base)))
base[i++] = *ptr++;
if (i < sizeof(base))
base[i] = NUL;
else
FATAL2("Index file name %s too long (max %u).\r",
base, (unsigned int)sizeof(base));
aux_fn = fn;
}
/**************************************************************************
* *
* Function: IntroduceBtxFile *
* Purpose: Tells Bibtex about the idx file we are about to *
* process. It fills in the FSSpec record of the file *
* descriptor for the idx file and initializes the variable *
* aux_fn to point to the name of the idx file. It also *
* invokes check_aux which performs some other initialization *
* such as extracting the base name of the file. *
* Inputs: specPtr is a pointer to the FSSpec record of the idx file *
* we're getting ready to process. *
* Outputs: None. *
* Exceptions: None. *
* Side Effects: Initializes the FileDescriptor structure for the idx *
* file. *
* Design: fns used to be an array of input files. Now it's just an *
* array with one element since we process just one idx file. *
* I couldn't think of a good way to reproduce this *
* capability on the Macintosh. I'm not really sure it's *
* necessary either. *
* This function uses a trick that appears in several other *
* places in this program. The name field of the FSSpec *
* record is declared to be a Str63 even though the maximum *
* length of a file name is 31 characters. Thus, it's always *
* safe to store a null character at the end of this string. *
* Then, a pointer to the first character of the string *
* points to a C style string. A pointer to the length byte *
* points to a Pascal style string. *
* Errors: None. *
* History: *
* 1.0 29-Jul-95 RJZ. Initial version. *
* *
**************************************************************************/
void IntroduceBtxFile(FSSpecPtr specPtr) {
gAuxDesc.spec = *specPtr;
gAuxDesc.spec.name[StrLength(gAuxDesc.spec.name) + 1] = '\0';
aux_fn = (char *) gAuxDesc.spec.name + 1;
// setup base name
check_aux((char *) aux_fn);
}